/*!
 * \file ParserAdapter.cpp
 * \project	WonderTrader
 *
 * \author Wesley
 * \date 2020/03/30
 *
 * \brief
 */
#include "ParserAdapter.h"
#include "WtDtRunner.h"
#include "WtHelper.h"

#include "../Share/CodeHelper.hpp"
#include "../Share/DLLHelper.hpp"
#include "../Share/StdUtils.hpp"
#include "../Share/StrUtil.hpp"

#include "../Includes/WTSContractInfo.hpp"
#include "../Includes/WTSDataDef.hpp"
#include "../Includes/WTSVariant.hpp"

#include "../WTSTools/WTSBaseDataMgr.h"
#include "../WTSTools/WTSLogger.h"

//////////////////////////////////////////////////////////////////////////
// ParserAdapter
ParserAdapter::ParserAdapter(WTSBaseDataMgr* bgMgr, WtDtRunner* runner)
    : _parser_api(NULL), _remover(NULL), _stopped(false), _bd_mgr(bgMgr),
      _dt_runner(runner), _cfg(NULL) {}

ParserAdapter::~ParserAdapter() {}

bool ParserAdapter::initExt(const char* id, IParserApi* api) {
    if (api == NULL)
        return false;

    _parser_api = api;
    _id = id;

    if (_parser_api) {
        _parser_api->registerSpi(this);

        if (_parser_api->init(NULL)) {
            ContractSet contractSet;
            WTSArray* ayContract = _bd_mgr->getContracts();
            WTSArray::Iterator it = ayContract->begin();
            for (; it != ayContract->end(); it++) {
                WTSContractInfo* contract =
                    STATIC_CONVERT(*it, WTSContractInfo*);
                contractSet.insert(contract->getFullCode());
            }

            ayContract->release();

            _parser_api->subscribe(contractSet);
            contractSet.clear();
        }
        else {
            WTSLogger::log_dyn(
                "parser", _id.c_str(), LL_ERROR,
                "[{}] Parser initializing failed: api initializing failed...",
                _id.c_str());
        }
    }

    return true;
}

bool ParserAdapter::init(const char* id, WTSVariant* cfg) {
    if (cfg == NULL)
        return false;

    _id = id;

    if (_cfg != NULL)
        return false;

    _cfg = cfg;
    _cfg->retain();

    {
        //加载模块
        if (cfg->getString("module").empty())
            return false;

        std::string module =
            DLLHelper::wrap_module(cfg->getCString("module"), "lib");
        ;

        if (!StdFile::exists(module.c_str())) {
            module = WtHelper::get_module_dir();
            module += "parsers/";
            module += DLLHelper::wrap_module(cfg->getCString("module"), "lib");
        }

        DllHandle hInst = DLLHelper::load_library(module.c_str());
        if (hInst == NULL) {
            WTSLogger::log_dyn("parser", _id.c_str(), LL_ERROR,
                               "[{}] Parser module {} loading failed",
                               _id.c_str(), module.c_str());
            return false;
        }
        else {
            WTSLogger::log_dyn("parser", _id.c_str(), LL_INFO,
                               "[{}] Parser module {} loaded", _id.c_str(),
                               module.c_str());
        }

        FuncCreateParser pFuncCreateParser =
            (FuncCreateParser)DLLHelper::get_symbol(hInst, "createParser");
        if (NULL == pFuncCreateParser) {
            WTSLogger::log_dyn("parser", _id.c_str(), LL_FATAL,
                               "[{}] Entrance function createParser not found",
                               _id.c_str());
            return false;
        }

        _parser_api = pFuncCreateParser();
        if (NULL == _parser_api) {
            WTSLogger::log_dyn("parser", _id.c_str(), LL_FATAL,
                               "[{}] Creating parser api failed", _id.c_str());
            return false;
        }

        _remover =
            (FuncDeleteParser)DLLHelper::get_symbol(hInst, "deleteParser");
    }

    const std::string& strFilter = cfg->getString("filter");
    if (!strFilter.empty()) {
        const StringVector& ayFilter = StrUtil::split(strFilter, ",");
        auto it = ayFilter.begin();
        for (; it != ayFilter.end(); it++) {
            _exchg_filter.insert(*it);
        }
    }

    std::string strCodes = cfg->getString("code");
    if (!strCodes.empty()) {
        const StringVector& ayCodes = StrUtil::split(strCodes, ",");
        auto it = ayCodes.begin();
        for (; it != ayCodes.end(); it++) {
            _code_filter.insert(*it);
        }
    }

    if (_parser_api) {
        _parser_api->registerSpi(this);

        if (_parser_api->init(cfg)) {
            ContractSet contractSet;
            if (!_code_filter.empty()) //优先判断合约过滤器
            {
                ExchgFilter::iterator it = _code_filter.begin();
                for (; it != _code_filter.end(); it++) {
                    //全代码,形式如SSE.600000,期货代码为CFFEX.IF2005
                    std::string code, exchg;
                    auto ay = StrUtil::split((*it).c_str(), ".");
                    if (ay.size() == 1)
                        code = ay[0];
                    else if (ay.size() == 2) {
                        exchg = ay[0];
                        code = ay[1];
                    }
                    else if (ay.size() == 3) {
                        exchg = ay[0];
                        code = ay[2];
                    }
                    WTSContractInfo* contract =
                        _bd_mgr->getContract(code.c_str(), exchg.c_str());
                    if (contract)
                        contractSet.insert(contract->getFullCode());
                    else {
                        //如果是品种ID，则将该品种下全部合约都加到订阅列表
                        WTSCommodityInfo* commInfo =
                            _bd_mgr->getCommodity(exchg.c_str(), code.c_str());
                        if (commInfo) {
                            const auto& codes = commInfo->getCodes();
                            for (const auto& c : codes) {
                                contractSet.insert(
                                    fmt::format("{}.{}", exchg, c.c_str()));
                            }
                        }
                    }
                }
            }
            else if (!_exchg_filter.empty()) {
                ExchgFilter::iterator it = _exchg_filter.begin();
                for (; it != _exchg_filter.end(); it++) {
                    const char* exchg = (*it).c_str();
                    WTSArray* ayContract = _bd_mgr->getContracts(exchg);
                    auto cnt = ayContract->size();
                    WTSArray::Iterator it = ayContract->begin();
                    for (; it != ayContract->end(); it++) {
                        WTSContractInfo* contract =
                            STATIC_CONVERT(*it, WTSContractInfo*);
                        contractSet.insert(contract->getFullCode());
                    }

                    ayContract->release();

                    WTSLogger::log_dyn(
                        "parser", _id.c_str(), LL_INFO,
                        "[{}] {} contracts of {} added to sublist...",
                        _id.c_str(), cnt, exchg);
                }
            }
            else {
                WTSArray* ayContract = _bd_mgr->getContracts();
                WTSArray::Iterator it = ayContract->begin();
                for (; it != ayContract->end(); it++) {
                    WTSContractInfo* contract =
                        STATIC_CONVERT(*it, WTSContractInfo*);
                    contractSet.insert(contract->getFullCode());
                }

                ayContract->release();
            }

            _parser_api->subscribe(contractSet);
            contractSet.clear();
        }
        else {
            WTSLogger::log_dyn(
                "parser", _id.c_str(), LL_ERROR,
                "[{}] Parser initializing failed: api initializing failed...",
                _id.c_str());
        }
    }
    else {
        WTSLogger::log_dyn(
            "parser", _id.c_str(), LL_ERROR,
            "[{}] Parser initializing failed: creating api failed...",
            _id.c_str());
    }

    return true;
}

void ParserAdapter::release() {
    _stopped = true;
    if (_parser_api) {
        _parser_api->release();
    }

    if (_remover)
        _remover(_parser_api);
    else
        delete _parser_api;
}

bool ParserAdapter::run() {
    if (_parser_api == NULL)
        return false;

    _parser_api->connect();
    return true;
}

void ParserAdapter::handleSymbolList(const WTSArray* aySymbols) {}

void ParserAdapter::handleTransaction(WTSTransData* transData) {
    if (_stopped)
        return;

    if (transData->actiondate() == 0 || transData->tradingdate() == 0)
        return;

    WTSContractInfo* contract =
        _bd_mgr->getContract(transData->code(), transData->exchg());
    if (contract == NULL)
        return;
}

void ParserAdapter::handleOrderDetail(WTSOrdDtlData* ordDetailData) {
    if (_stopped)
        return;

    if (ordDetailData->actiondate() == 0 || ordDetailData->tradingdate() == 0)
        return;

    WTSContractInfo* contract =
        _bd_mgr->getContract(ordDetailData->code(), ordDetailData->exchg());
    if (contract == NULL)
        return;
}

void ParserAdapter::handleOrderQueue(WTSOrdQueData* ordQueData) {
    if (_stopped)
        return;

    if (ordQueData->actiondate() == 0 || ordQueData->tradingdate() == 0)
        return;

    WTSContractInfo* contract =
        _bd_mgr->getContract(ordQueData->code(), ordQueData->exchg());
    if (contract == NULL)
        return;
}

void ParserAdapter::handleQuote(WTSTickData* quote, uint32_t procFlag) {
    if (quote == NULL || _stopped || quote->actiondate() == 0 ||
        quote->tradingdate() == 0)
        return;

    if (_dt_runner)
        _dt_runner->proc_tick(quote);
}

void ParserAdapter::handleParserLog(WTSLogLevel ll, const char* message) {
    if (_stopped)
        return;

    WTSLogger::log_raw_by_cat("parser", ll, message);
}

IBaseDataMgr* ParserAdapter::getBaseDataMgr() { return _bd_mgr; }

//////////////////////////////////////////////////////////////////////////
// ParserAdapterMgr
void ParserAdapterMgr::release() {
    for (auto it = _adapters.begin(); it != _adapters.end(); it++) {
        it->second->release();
    }

    _adapters.clear();
}

bool ParserAdapterMgr::addAdapter(const char* id, ParserAdapterPtr& adapter) {
    if (adapter == NULL || strlen(id) == 0)
        return false;

    auto it = _adapters.find(id);
    if (it != _adapters.end()) {
        WTSLogger::error(" Same name of parsers: %s", id);
        return false;
    }

    _adapters[id] = adapter;

    return true;
}

ParserAdapterPtr ParserAdapterMgr::getAdapter(const char* id) {
    auto it = _adapters.find(id);
    if (it != _adapters.end()) {
        return it->second;
    }

    return ParserAdapterPtr();
}

void ParserAdapterMgr::run() {
    for (auto it = _adapters.begin(); it != _adapters.end(); it++) {
        it->second->run();
    }

    WTSLogger::info("{} parsers started", _adapters.size());
}